import "./ContentPage.scss";
import {ReactComponentPage} from "../../class/ReactComponentPage";
import {RouteComponentProps, StaticContext} from "react-router";
import {createRef} from "react";
import React from "react";
import {TableArticleList} from "../../../common/class/TableArticleList";
import {Button, message, Icon, Input, Spin} from "antd";
import {Link} from "react-router-dom";
import {MangaSite} from "../../../common/class/MangaSite/MangaSite";
import {ToNaRiYJ} from "../../../common/class/MangaSite/ToNaRiYJ/ToNaRiYJ";
import {GanGanOnline} from "../../../common/class/MangaSite/GanGanOnline/GanGanOnline";
import {LocalManga} from "../../../common/class/MangaSite/LocalManga/LocalManga";
import {ManHuaDui} from "../../../common/class/MangaSite/ManHuaDui/ManHuaDui";
import {DMZJ} from "../../../common/class/MangaSite/DMZJ/DMZJ";

export namespace ContentPage {
    interface RouteParams {
        articleId: string;
    }
    export interface State extends ReactComponentPage.State {
        articleInfo: Partial<TableArticleList.Data>;
        mouseOn: boolean;
        showPageIndex: [number, number];
        pageList: MangaSite.ImgItemInfo[];
        loading: boolean;
    }

    export interface Props extends ReactComponentPage.Props, RouteComponentProps<RouteParams, StaticContext, any> {
    }

    export type NoopFunc = () => void;
}

export class ContentPage extends ReactComponentPage<ContentPage.Props, ContentPage.State> {
    public readonly state: ContentPage.State = {
        articleInfo: {
            name: "",
        },
        mouseOn: false,
        showPageIndex: [0, 1],
        pageList: [],
        loading: true,
    };
    protected refCanvas = createRef<HTMLCanvasElement>();
    protected canvasElm: HTMLCanvasElement;
    protected halfCanvas: HTMLCanvasElement;
    protected drawer: CanvasRenderingContext2D;
    protected containPageNum: number = 2;
    protected refStartInput = createRef<Input>();
    protected websiteTool: MangaSite;
    public render() {
        const articleInfo = this.state.articleInfo;
        return (
            <div
                className={this.getClsName("content-page-component")}
                onMouseOver={this.whenMouseOver.bind(this)}
                onMouseLeave={this.whenMouseLeave.bind(this)}
                onClick={this.clickSpace.bind(this)}
            >
                {this.showSpin()}
                <div className="header-part">
                    <h3>{articleInfo.name}</h3>
                    <div className="return-btns">
                        <Button type={"primary"}>
                            <Link to={"/read/articles/" + articleInfo.book_id}>返回目录</Link>
                        </Button>
                    </div>
                </div>
                {this.getToPageBtn()}
                <canvas ref={this.refCanvas}/>
                <div className={"footer-part"}>
                    <div className={"render-select"}>
                        <Input
                            ref={this.refStartInput}
                            defaultValue={this.state.showPageIndex[0]}
                            min={0}
                            max={this.state.pageList.length - 1}
                            type={"number"}
                        />
                        <Button type={"default"} onClick={this.renderIndex.bind(this)}>开始渲染</Button>
                        <Button type={"primary"} onClick={(evt) => this.savePic()}>下载一屏</Button>
                        <Button type={"primary"} onClick={this.savePicLeft.bind(this)}>下载左图</Button>
                        <Button type={"primary"} onClick={this.savePicRight.bind(this)}>下载右图</Button>
                        <Button type={"primary"} onClick={(evt) => this.saveAllPic()}>下载整话</Button>
                    </div>
                </div>
            </div>
        );
    }
    public componentDidMount(): void {
        this.setDrawer();
        this.getArticleInfo();
        this.listenResize();
    }
    public componentWillUnmount(): void {
        this.updateArticleReadNum();
        this.removeListenResize();
    }
    public getClsName(clsName: string = ""): string {
        if (this.state.mouseOn) {
            clsName += " mouse-on ";
        } else {
            clsName += " mouse-leave ";
        }
        return super.getClsName(clsName);
    }
    public saveAllPic() {
        this.autoSaveAllPic();
    }
    public savePic(part: "left" | "right" | "whole" = "whole") {
        if (part === "whole") {
            const showPageIndexList = this.state.showPageIndex;
            const nameIndex = (showPageIndexList[0] + 1) + "_" + (showPageIndexList[1] + 1);
            const base64Data = this.canvasElm.toDataURL("jpg");
            return this.writeImgInBase64AutoFillName(nameIndex, base64Data);
        } else {
            return this.savePicPart(part);
        }
    }
    public savePicPart(part: "left" | "right" = "left") {
        const showPageIndexList = this.state.showPageIndex;
        let index = 1;
        if (part === "right") {
            index = 0;
        }
        const base64Data = this.websiteTool.savePart(part);
        return this.writeImgInBase64AutoFillName(showPageIndexList[index] + 1, base64Data);
    }
    public savePicLeft() {
        return this.savePicPart();
    }
    public savePicRight() {
        return this.savePicPart("right");
    }
    protected writeImgInBase64AutoFillName(nameIndex: string | number, base64Data: string) {
        const name = this.websiteTool.getPicAbsName(nameIndex);
        return this.writeImgInBase64(name, base64Data);
    }
    protected writeImgInBase64(name: string, base64Data: string) {
        return this.websiteTool.writeImgInBase64(name, base64Data)
            .then(() => {
                const msg = `下载图片成功: ${name}`;
                message.success(msg);
            })
            .catch((err) => {
                console.error(err);
                message.error("下载图片失败");
            });
    }
    protected listenResize() {
        const resizeFunc = this.whenResize.bind(this);
        window.addEventListener("resize", resizeFunc);
    }
    protected removeListenResize() {
        const resizeFunc = this.whenResize.bind(this);
        window.removeEventListener("resize", resizeFunc);
    }
    protected showSpin() {
        if (this.state.loading) {
            return (<Spin className={"loading-state"} size={"large"} />);
        }
        return null;
    }
    protected whenResize() {
        this.canvasElm.width = window.innerWidth;
        this.canvasElm.height = window.innerHeight;
        this.drawer.clearRect(0, 0, this.canvasElm.width, this.canvasElm.height);
        this.drawBg();
        this.drawScreenReferShowPageIndex();
    }
    protected renderIndex() {
        const input = this.refStartInput.current;
        let startIndex = parseInt(input.state.value) || 0;
        let list: [number, number];
        if (startIndex >= this.state.pageList.length - 1) {
            list = [ this.state.pageList.length - 2, this.state.pageList.length - 1 ];
        } else {
            if (startIndex <= 0) {
                startIndex = 0;
            }
            list = [startIndex, startIndex + 1];
        }
        this.setState({
            showPageIndex: list,
        }, () => {
            this.drawScreenReferShowPageIndex();
        });
    }
    protected getToPageBtn() {
        const pageIndexList = this.state.showPageIndex;
        const pageList = this.state.pageList;
        if (!pageList.length) {
            return [];
        }
        const firstPageInfo = pageList[pageIndexList[0]];
        const btnList: JSX.Element[] = [];
        if (firstPageInfo.imgIndex !== 1) {
            btnList.push(<Icon key={"right"} type="right-circle" onClick={this.prevPage.bind(this)}/>);
        }
        if (firstPageInfo.imgIndex >= pageList.length) {
            return btnList;
        }
        const secondPageInfo = pageList[pageIndexList[1]];
        if (secondPageInfo.imgIndex >= pageList.length) {
            return btnList;
        }
        btnList.push(<Icon key={"left"} type="left-circle" onClick={this.nextPage.bind(this)}/>);
        return btnList;
    }
    protected setDrawer() {
        const canvasElm = this.refCanvas.current;
        canvasElm.width = window.innerWidth;
        canvasElm.height = window.innerHeight;
        this.canvasElm = canvasElm;
        this.drawer = canvasElm.getContext("2d");
    }
    protected getSiteToolBy(articleInfo: MangaSite.IArticleBaseInfo): MangaSite {
        switch (articleInfo.download_method) {
            case "tonariYJ":
                return new ToNaRiYJ(this.canvasElm, articleInfo);
            case "GanGanOnline":
                return new GanGanOnline(this.canvasElm, articleInfo);
            case "ManHuaDui":
                return new ManHuaDui(this.canvasElm, articleInfo);
            case "DMZJ":
                return new DMZJ(this.canvasElm, articleInfo);
            default:
                return new LocalManga(this.canvasElm, articleInfo);
        }
    }
    protected prepareInfo() {
        this.setState({
            loading: true,
        });
        this.drawBg();
        const articleInfo = this.state.articleInfo;
        this.websiteTool = this.getSiteToolBy(articleInfo as any);
        this.websiteTool
            .getImgList()
            .then((imgList) => {
                this.logList(imgList);
            }).catch((err) => {
                console.error(err);
                message.error("获取图片列表出错");
            });
    }
    protected logList(imgList: MangaSite.ImgItemInfo[]) {
        this.updateArticleImgNum(imgList.length);
        this.setState({
            pageList: imgList,
            showPageIndex: [0, 1],
        }, () => {
            this.drawScreenReferShowPageIndex();
        });
    }
    protected drawScreenReferShowPageIndex(cb?: ContentPage.NoopFunc) {
        this.setState({
            loading: true,
        });
        return this.loadImgByIndexList(this.state.showPageIndex)
            .then(() => {
                try {
                    this.drawScreen();
                    this.setState({
                        loading: false,
                    }, () => {
                        if (typeof cb === "function") {
                            cb();
                        }
                    });
                } catch (err) {
                    message.error("绘制图片时出错");
                    console.error(err);
                }
            })
            .catch((err) => {
                message.error("获取图片出错");
                console.error(err);
            });
    }
    protected loadImgByIndexList(indexList: number[]) {
        const list: Array<Promise<HTMLImageElement>> = [];
        for (const index of indexList) {
            const imgInfo = this.state.pageList[index];
            if (imgInfo) {
                const item = this.websiteTool.loadImg(imgInfo);
                list.push(item);
            } else {
                break;
            }
        }
        return Promise.all(list);
    }
    protected drawScreen() {
        const [ rightIndex, leftIndex ] = this.state.showPageIndex;
        this.drawBg();
        const rightImg = this.getImgElmByIndex(rightIndex);
        const leftImg = this.getImgElmByIndex(leftIndex);
        if (rightImg) {
            this.drawImgOnScreen(rightImg, "right");
        }
        if (leftImg) {
            this.drawImgOnScreen(leftImg, "left");
        }
        this.loadImgByIndexList([
            this.state.showPageIndex[1] + 1,
            this.state.showPageIndex[1] + 2,
        ]);
    }
    protected drawImgOnScreen(img: HTMLImageElement, position: MangaSite.TDrawPosition = "left") {
        this.websiteTool.drawPage(img, position);
    }
    protected getImgElmByIndex(index: number): HTMLImageElement | null {
        const imgInfo = this.state.pageList[index];
        if (imgInfo) {
            const img = this.websiteTool.getImgElmFromCache(imgInfo.src);
            return img;
        }
        return null;
    }
    protected clickSpace(evt: React.MouseEvent<HTMLElement, MouseEvent>) {
        // evt.persist();
        const cx = window.innerWidth / 2;
        const cy = window.innerHeight / 2;
        const dx = Math.abs(cx - evt.clientX);
        const dy = Math.abs(cy - evt.clientY);
        const ox = 100;
        const oy = 100;
        if (dx <= ox && dy <= oy) {
            this.whenClickCenter();
        } else if (!this.state.mouseOn) {
            if (
                evt.clientX < ox
            ) {
                this.whenClickLeft();
            } else if (
                window.innerWidth - evt.clientX < ox
            ) {
                this.whenClickRight();
            }
        }
    }
    protected whenClickLeft() {
        const secondIndex = this.state.showPageIndex[1];
        if (secondIndex < this.state.pageList.length - 1) {
            this.nextPage();
        }
    }
    protected whenClickRight() {
        const index = this.state.showPageIndex[0];
        if (index > 0) {
            this.prevPage();
        }
    }
    protected whenClickCenter() {
        const nextState = !this.state.mouseOn;
        this.setState({
            mouseOn: nextState,
        });
    }
    protected drawBg() {
        const canvasElm = this.canvasElm;
        const drawer = this.drawer;
        drawer.fillStyle = "grey";
        drawer.fillRect(0, 0, canvasElm.width, canvasElm.height);
    }
    protected getArticleInfo() {
        const articleId = parseInt(this.props.match.params.articleId);
        if (!articleId) {
            message.error("错误的索引值");
            return;
        }
        TableArticleList
            .getInstance()
            .select()
            .where("id", articleId)
            .find()
            .then((row) => {
                this.setState({
                    articleInfo: row,
                }, () => {
                    this.prepareInfo();
                });
            })
            .catch((err) => {
                console.error(err);
                message.error("获取内容出错");
            });
    }
    protected whenMouseOver() {
        this.setState({
            mouseOn: true,
        });
    }
    protected whenMouseLeave() {
        this.setState({
            mouseOn: false,
        });
    }
    protected prevPage() {
        const list = this.state.showPageIndex.map((pageIndex) => {
            return pageIndex - 1;
        }) as any;
        this.renderPageByList(list);
    }
    protected nextPage() {
        const list = this.state.showPageIndex.map((pageIndex) => {
            return pageIndex + 1;
        }) as any;
        this.renderPageByList(list);
    }
    protected renderPageByList(list: [number, number]) {
        const pageList = this.state.pageList;
        let newList = list.filter((item) => {
            return (item >= 0) && (item < pageList.length);
        });
        if (newList.length) {
            if (newList.length === 1) {
                const first = newList[0];
                if (first === 0) {
                    newList = [first, first + 1];
                } else {
                    newList = [first, first - 1];
                }
            }
            this.setState({
                showPageIndex: (newList as [number, number]),
            }, () => {
                this.drawScreenReferShowPageIndex();
            });
        } else {
            message.error(`请输入的序号: [0-${pageList.length - 1}]`);
        }
    }
    protected autoSaveAllPic(startIndex: number = 0) {
        const maxPageIndex = this.state.pageList.length - 1;
        if (startIndex >= maxPageIndex) {
            return ;
        }
        this.setState({
            showPageIndex: [startIndex, startIndex + 1],
        }, () => {
            this.drawScreenReferShowPageIndex(() => {
                let nextPageIndex = this.state.showPageIndex[1] + 1;
                if (this.state.showPageIndex[0] >= maxPageIndex) {
                    message.success("完成下载");
                    return ;
                }
                this.savePicRight()
                    .then(() => {
                        this.savePicLeft()
                            .then(() => {
                                if (nextPageIndex === maxPageIndex) {
                                    nextPageIndex = maxPageIndex - 1;
                                }
                                this.autoSaveAllPic(nextPageIndex);
                            });
                    });
            });
        });
    }
    protected updateArticleImgNum(num: number): Promise<void> {
        if (!num) {
            return Promise.resolve() as Promise<void>;
        }
        const articleInfo = this.state.articleInfo;
        return TableArticleList
            .getInstance()
            .sqlSet("img_num", num)
            .where("id", articleInfo.id)
            .update();
    }
    protected updateArticleReadNum(): Promise<number> {
        const articleInfo = this.state.articleInfo;
        const oldReadNum = articleInfo.read_num || 0;
        const newReadNum = this.state.showPageIndex[1] || 0;
        if (oldReadNum >= newReadNum) {
            return Promise.resolve(oldReadNum);
        }
        return TableArticleList
            .getInstance()
            .sqlSet("read_num", newReadNum)
            .where("id", articleInfo.id)
            .update()
            .then(() => {
                return newReadNum;
            });
    }
}
